using System;
using System.Xml;
using DesignByContract;
using Outcoding.GraphGenerator.Entities;
using Outcoding.GraphGenerator.Util.Logging;

namespace Outcoding.GraphGenerator.Composition{
    public class CategoryLabelBuilder : BuilderBase{
        #region Attributes

        /*  Table Cell dimensions   */
        private readonly string cellHeightAttr = "cell-height";
        private readonly string cellWidthAttr = "cell-width";
        private string colorAttr = "color";
        private string fontColorAttr = "font-color";
        private string fontDecorationAttr = "font-decoration";

        /*font attributes*/
        private string fontNameAttr = "font-name";
        private string fontSizeAttr = "font-size";
        private string hAlignAttr = "halign";
        private string isSmoothAttr = "smoothed";
        private string markerBackgroundAttr = "marker-background";
        private string markerForegroundAttr = "marker-foreground";
        private string markerSizeAttr = "marker-size";
        private string markerStyleAttr = "marker-style";
        private string styleAttr = "style";
        private string weightAttr = "weight";

        #endregion

        private readonly string mNodeName = XmlTagNames.categorylabel.ToString();

        private XmlNode mNode;

        private string mNodePath{
            get { return "./" + mNodeName; }
        }

        public XmlNode Node{
            get { return mNode; }
            set { mNode = value; }
        }

        public override void SelectNode(XmlDocument document){
            //HACK: this is done in order to work with labelcollection
        }

        public override void Compose(){
            try{
                BuildObject(mNode);
            }
            catch (PreconditionException preExc){
                LogManager.Instance.LogWarning("Label entity could not be created; process aborted.", preExc);
            }
        }

        public override void Compose(XmlNode node){
            mNode = node.SelectSingleNode(mNodePath);
            try{
                BuildObject(mNode);
            }
            catch (PreconditionException preExc){
                LogManager.Instance.LogWarning("Label entity could not be created; process aborted.", preExc);
            }
        }

        public override void AppendToParent(object parent){
            if (parent is LabelCollection)
                (parent as LabelCollection).Add((CategoryLabel) mProduct);
        }

        private void BuildObject(XmlNode labelXmlNode){
            var label = new CategoryLabel();
            try{
                //line attributes
                if (labelXmlNode.Attributes[styleAttr] != null)
                    label.Border.Style = ParseStyleAttribute(labelXmlNode);
                if (labelXmlNode.Attributes[weightAttr] != null)
                    label.Border.Weight = ParseWeightAttribute(labelXmlNode);
                if (labelXmlNode.Attributes[colorAttr] != null)
                    label.Border.Color = ParseColorAttribute(labelXmlNode);
                if (labelXmlNode.Attributes[isSmoothAttr] != null)
                    label.IsSmooth = ParseIsSmoothAttribute(labelXmlNode);

                //marker attributes
                if (labelXmlNode.Attributes[markerStyleAttr] != null)
                    label.Marker.Style = ParseMarkerStyleAttribute(labelXmlNode);
                if (labelXmlNode.Attributes[markerSizeAttr] != null)
                    label.Marker.Size = ParseMarkerSizeAttribute(labelXmlNode);
                if (labelXmlNode.Attributes[markerForegroundAttr] != null)
                    label.Marker.Foreground = ParseMarkerForegroundAttribute(labelXmlNode);
                if (labelXmlNode.Attributes[markerBackgroundAttr] != null)
                    label.Marker.Background = ParseMarkerBackgroundAttribute(labelXmlNode);

                //Table dimension attributes
                if (labelXmlNode.Attributes[cellHeightAttr] != null)
                    label.CellHeight = ParseCellHeightAttribute(labelXmlNode);
                if (labelXmlNode.Attributes[cellWidthAttr] != null)
                    label.CellWidth = ParseCellWidthAttribute(labelXmlNode);

                //font attributes
                if (labelXmlNode.Attributes[fontNameAttr] != null)
                    label.FontName = ParseFontNameAttribute(labelXmlNode);
                if (labelXmlNode.Attributes[fontSizeAttr] != null)
                    label.FontSize = ParseFontSizeAttribute(labelXmlNode);
                if (labelXmlNode.Attributes[fontDecorationAttr] != null){
                    label.IsFontBold = ParseIsFontBoldAttribute(labelXmlNode);
                    label.IsFontItalic = ParseIsFontItalicAttribute(labelXmlNode);
                    label.IsFontUnderline = ParseIsFontUnderlineAttribute(labelXmlNode);
                }
                if (labelXmlNode.Attributes[fontColorAttr] != null)
                    label.Color = ParseFontColorAttribute(labelXmlNode);
                if (labelXmlNode.Attributes[hAlignAttr] != null)
                    label.HorizontalAlignment = ParseHorizontalAlignmentAttribute(labelXmlNode);

                label.Text = ParseTextValue(labelXmlNode);
            }
            catch (PreconditionException preExc){
                //log error
                label = null;
                throw;
            }
            mProduct = label;
        }

        private XlLineStyle ParseStyleAttribute(XmlNode majorGridlineXmlNode){
            Check.Require(majorGridlineXmlNode.Attributes[styleAttr] != null, "style attribute not present");

            return XlLineStyleHelper.ConvertFromString(majorGridlineXmlNode.Attributes[styleAttr].Value);
        }

        private XlBorderWeight ParseWeightAttribute(XmlNode majorGridlineXmlNode){
            Check.Require(majorGridlineXmlNode.Attributes[weightAttr] != null, "weight attribute not present");

            return XlBorderWeightHelper.ConvertFromString(majorGridlineXmlNode.Attributes[weightAttr].Value);
        }

        private long ParseColorAttribute(XmlNode majorGridlineXmlNode){
            Check.Require(majorGridlineXmlNode.Attributes[colorAttr] != null, "color attribute not present");

            return Entities.Util.ColorTranslation(majorGridlineXmlNode.Attributes[colorAttr].Value);
        }

        private bool ParseIsSmoothAttribute(XmlNode majorGridlineXmlNode){
            Check.Require(majorGridlineXmlNode.Attributes[isSmoothAttr] != null, "smoothed attribute not present");

            return Boolean.Parse(majorGridlineXmlNode.Attributes[isSmoothAttr].Value);
        }

        private XlMarkerStyle ParseMarkerStyleAttribute(XmlNode majorGridlineXmlNode){
            Check.Require(majorGridlineXmlNode.Attributes[markerStyleAttr] != null, "marker-style attribute not present");

            return XlMarkerStyleHelper.ConvertFromString(majorGridlineXmlNode.Attributes[markerStyleAttr].Value);
        }

        private int ParseMarkerSizeAttribute(XmlNode majorGridlineXmlNode){
            Check.Require(majorGridlineXmlNode.Attributes[markerSizeAttr] != null, "marker-size attribute not present");

            return Int32.Parse(majorGridlineXmlNode.Attributes[markerSizeAttr].Value);
        }

        private long ParseMarkerForegroundAttribute(XmlNode majorGridlineXmlNode){
            Check.Require(majorGridlineXmlNode.Attributes[markerForegroundAttr] != null, "color attribute not present");

            return Entities.Util.ColorTranslation(majorGridlineXmlNode.Attributes[markerForegroundAttr].Value);
        }

        private long ParseMarkerBackgroundAttribute(XmlNode majorGridlineXmlNode){
            Check.Require(majorGridlineXmlNode.Attributes[markerBackgroundAttr] != null, "color attribute not present");

            return Entities.Util.ColorTranslation(majorGridlineXmlNode.Attributes[markerBackgroundAttr].Value);
        }

        private int ParseCellHeightAttribute(XmlNode majorGridlineXmlNode){
            Check.Require(majorGridlineXmlNode.Attributes[cellHeightAttr] != null, "cell-height attribute not present");

            return Int32.Parse(majorGridlineXmlNode.Attributes[cellHeightAttr].Value);
        }

        private int ParseCellWidthAttribute(XmlNode majorGridlineXmlNode){
            Check.Require(majorGridlineXmlNode.Attributes[cellWidthAttr] != null, "cell-width attribute not present");

            return Int32.Parse(majorGridlineXmlNode.Attributes[cellWidthAttr].Value);
        }

        private string ParseFontNameAttribute(XmlNode labelXmlNode){
            Check.Require(labelXmlNode.Attributes[fontNameAttr] != null, "font-name attribute not present");
            return labelXmlNode.Attributes[fontNameAttr].Value;
        }

        private int ParseFontSizeAttribute(XmlNode labelXmlNode){
            Check.Require(labelXmlNode.Attributes[fontSizeAttr] != null, "font-size attribute not present");
            return Int32.Parse(labelXmlNode.Attributes[fontSizeAttr].Value);
        }

        private bool ParseIsFontBoldAttribute(XmlNode labelXmlNode){
            Check.Require(labelXmlNode.Attributes[fontDecorationAttr] != null, "font-decoration attribute not present");
            return labelXmlNode.Attributes[fontDecorationAttr].Value.Contains("bold");
        }

        private bool ParseIsFontItalicAttribute(XmlNode labelXmlNode){
            Check.Require(labelXmlNode.Attributes[fontDecorationAttr] != null, "font-decoration attribute not present");
            return labelXmlNode.Attributes[fontDecorationAttr].Value.Contains("italic");
        }

        private bool ParseIsFontUnderlineAttribute(XmlNode labelXmlNode){
            Check.Require(labelXmlNode.Attributes[fontDecorationAttr] != null, "font-decoration attribute not present");
            return labelXmlNode.Attributes[fontDecorationAttr].Value.Contains("underline");
        }

        private PPAlignment ParseHorizontalAlignmentAttribute(XmlNode labelXmlNode){
            Check.Require(labelXmlNode.Attributes[hAlignAttr] != null, "horizontal alignment attribute not present");
            return Entities.Util.ParseEnum<PPAlignment>(labelXmlNode.Attributes[hAlignAttr].Value);
        }

        private long ParseFontColorAttribute(XmlNode majorGridlineXmlNode){
            Check.Require(majorGridlineXmlNode.Attributes[fontColorAttr] != null, "font-color attribute not present");

            return Entities.Util.ColorTranslation(majorGridlineXmlNode.Attributes[fontColorAttr].Value);
        }

        private string ParseTextValue(XmlNode labelXmlNode){
            return labelXmlNode.InnerText.Trim();
        }
    }
}